package com.mz.common.config;

import com.mz.common.dto.GlobalException;
import com.mz.common.dto.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolationException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     *  处理请求参数无法转换成接口方法需要的参数的情形
     * **/
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public R doMessageNotReadableException(HttpMessageNotReadableException exception ){
        String content = exception.getMessage();
        log.error("content: {}", exception);
        if( content.indexOf("Cannot deserialize value of type `java.util.Date` from String") > -1 ){
            return  R.fail(1002,"日期时间格式错误,需要为 yyyy-MM-dd HH:mm:ss");
        }

        if( content.startsWith("Required request body is missing") ){
            return  R.fail(1003, "请传入消息请求体 httpBody");
        }
        return  R.fail(500, exception.getMessage());
    }



/**************************************************************************/
    /**
     * application/x-www-form-urlencoded 表达形式下，直接在方法参数中添加 @NotNull, @Length 等验证参数验证不同时抛出的异常。
     * */
    @ExceptionHandler(ConstraintViolationException.class)
    public R doConstraintViolationException( ConstraintViolationException exception ){

        log.error("{}",exception);
        System.out.println("doConstraintViolationException...");
        Map map = new HashMap();
        String content = exception.getMessage();
        String[] split = content.split(",");
        for( String eleString : split ){
            String[] keyValue = eleString.split(":");
            String key = keyValue[0];
            String value = keyValue[1];
            Integer index = key.indexOf(".");
            if( index > -1 ){
                map.put(key.substring(index+1), value);
            }
        }
        return R.fail(map);
    }


/**************************************************************************/
    /**
     * application/x-www-form-urlencoded 表单形式的对象使用 @Valid, 且对象的属性参数验证不通过时抛出的异常。
     * application/json json形式的对象使用 @Valid, 且对象的属性参数验证不通过时抛出的异常。
     * **/
    @ExceptionHandler(BindException.class)
    public R doBindException( BindException exception ){

        System.out.println("BIndException: .....");
        log.error( "{}", exception.getMessage());
        BindingResult bindingResult = exception.getBindingResult();
        /**
         * 1、收集所有的没有验证通过的属性，对应的报错。
         * 2、将所有的属性报错信息，拼接成为一个字符串信息。
         * 3、fieldError.getField()  获取未验证通过的属性名称。
         *   fieldError.getDefaultMessage() 获取未验证通过时预设的 message。
         * */
        List<FieldError> fieldErrors = bindingResult.getFieldErrors();
        StringBuffer stringBuffer = new StringBuffer();

        Map map = new HashMap<String,String>();
        fieldErrors.forEach(fieldError -> {
//            StringBuffer content = stringBuffer.append(  fieldError.getDefaultMessage()).append(",");
            map.put( fieldError.getField(), fieldError.getDefaultMessage() );
        });

        log.error(stringBuffer.toString());
        return R.fail( map );
    }


    /**
     * 自定义异常处理
     * **/
    @ExceptionHandler(GlobalException.class)
    public R handleCustomException( GlobalException globalException ){
        log.error("{}", globalException);
        return R.fail(globalException.getCode(), globalException.getMessage());
    }

    /**
     * 系统异常
     * */
    @ExceptionHandler( Exception.class )
    public R handleSystemException( Exception exception ){
        log.error("{}", exception);
        return R.fail(500, exception.getMessage());
    }
}